const https = require('https');
const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');

// ========== Configurable Items ==========
const CONFIG_URL = 'https://gitee.com/luckylqm/config/raw/master/gitConfig/htrip_git_clone_config.ini';
const TEMP_DIR = 'D:\\data\\tmp'; // Temporary directory path
const BASE_DIR = 'D:\\ws'; // Base directory path
const GIT_PATH = '"d:\\env\\git\\2.49.0\\bin\\git.exe"'; // Git installation path (note quotes and escape)
const BAT_FILE_PREFIX = 'git_clone_menu'; // Prefix for the batch file name
// ==============================

function downloadIniFile(url) {
    return new Promise((resolve, reject) => {
        let data = '';
        https.get(url, (res) => {
            if (res.statusCode !== 200) {
                return reject(new Error(`Request failed, status code: ${res.statusCode}`));
            }
            res.on('data', chunk => data += chunk);
            res.on('end', () => resolve(data));
        }).on('error', err => reject(err));
    });
}

function parseIni(content) {
    const result = {};
    let currentSection = null;

    const lines = content.split(/\r?\n/)
        .map(line => line.trim())
        .filter(line => line.length > 0 && !line.startsWith('#') && !line.startsWith(';'));

    for (let line of lines) {
        if (line.startsWith('[') && line.endsWith(']')) {
            currentSection = line.substring(1, line.length - 1).trim();
            if (!result[currentSection]) {
                result[currentSection] = [];
            }
        } else if (currentSection) {
            const match = line.match(/=(.+)/);
            if (match) {
                result[currentSection].push(match[1].trim());
            } else {
                result[currentSection].push(line);
            }
        }
    }

    return result;
}

function ensureDirectoryExists(dirPath) {
    if (!fs.existsSync(dirPath)) {
        fs.mkdirSync(dirPath, { recursive: true });
        console.log(`✅ Created directory: ${dirPath}`);
    }
}

function generateBat(groups, outputPath) {
    const bat = [];

    function batLine(...parts) {
        return parts.join('');
    }

    // Write header
    bat.push('@echo off');
    bat.push(':: Set code page to UTF-8');
    bat.push('chcp 65001 >nul');
    bat.push('');
    bat.push(`set "baseDir=${BASE_DIR}"`);
    bat.push(`set "gitPath=${GIT_PATH}"`);
    bat.push('');

    // Write menu
    bat.push(':menu');
    bat.push('cls');
    bat.push(`echo.`);
    bat.push(`echo git clone project to %baseDir%:`);

    const groupNames = Object.keys(groups);
    const menuMap = {};

    groupNames.forEach((groupName, index) => {
        const optionIndex = index + 1;
        const labelName = groupName.replace(/[.-]/g, '_'); // Replace illegal characters
        menuMap[optionIndex] = labelName;
        bat.push(`echo ${optionIndex}. ${groupName}`);
    });

    bat.push(`echo 0. all`);
    bat.push('set /p choice=Enter (1, 2, 3, 4, 0):');

    bat.push('if /i "%choice%"=="0" goto clone_all');
    groupNames.forEach((_, index) => {
        const optionIndex = index + 1;
        const groupName = groupNames[index];
        const shortLabel = groupName.includes('.') ? groupName.split('.')[1] : groupName;
        const labelName = shortLabel.replace(/[.-]/g, '_');
        bat.push(`if "%choice%"=="${optionIndex}" call :do_${labelName}`);
    });

    bat.push('echo Invalid input. Please enter a valid option.');
    bat.push('pause');
    bat.push('goto menu');
    bat.push('');

    // Write each group function
    groupNames.forEach(groupName => {
        const shortLabel = groupName.includes('.') ? groupName.split('.')[1] : groupName;
        const labelName = shortLabel.replace(/[.-]/g, '_');
        const urls = groups[groupName];

        bat.push(`:do_${labelName}`);

        // Construct full project path: like htrip.mall -> %baseDir%\htrip\mall
        const pathParts = groupName.split('.');
        const projectPath = `%baseDir%\\${pathParts.join('\\')}`;
        bat.push(`call :clone_project "${projectPath}" ^`);

        urls.forEach((url, idx) => {
            const isLast = idx === urls.length - 1;
            bat.push(`    "${url}"${isLast ? '' : ' ^'}`);
        });

        bat.push('goto :EOF');
        bat.push('');
    });

    // Write :clone_all function
    bat.push(':clone_all');
    groupNames.forEach(groupName => {
        const shortLabel = groupName.includes('.') ? groupName.split('.')[1] : groupName;
        const labelName = shortLabel.replace(/[.-]/g, '_');
        bat.push(`call :do_${labelName}`);
    });
    bat.push('goto :EOF');
    bat.push('');

    // Write :clone_project function
    bat.push(`:clone_project`);
    bat.push(`setlocal`);
    bat.push(`set "projectDir=%~1"`);  // Receive full path
    bat.push(`shift`);
    bat.push(``);
    bat.push(`if not exist "%projectDir%" (`);
    bat.push(`    echo Directory %projectDir% does not exist. Creating...`);
    bat.push(`    mkdir "%projectDir%"`);
    bat.push(`    if errorlevel 1 (`);
    bat.push(`        echo Failed to create directory %projectDir%. Please check permissions.`);
    bat.push(`        endlocal`);
    bat.push(`        pause`);
    bat.push(`        exit /b 1`);
    bat.push(`    )`);
    bat.push(`)`);
    bat.push(``);
    bat.push(`cd /d "%projectDir%"`);
    bat.push(`echo Current directory is:`);
    bat.push(`cd`);
    bat.push(``);
    bat.push(`:loop_repos`);
    bat.push(`if "%~1"=="" goto :EOF`);
    bat.push(``);
    bat.push(`for %%F in (%~1) do set "repoName=%%~nF"`);  // Extract repo name
    bat.push(`set "repoFullPath=%projectDir%\\%repoName%"`);
    bat.push(``);
    bat.push(`if exist "%repoFullPath%" (`);
    bat.push(`    echo Repository %repoName% already exists. Pulling latest changes...`);
    bat.push(`    cd /d "%repoFullPath%"`);
    bat.push(`    %gitPath% pull`);
    bat.push(`    if errorlevel 1 (`);
    bat.push(`        echo Failed to pull repository %repoName%.`);
    bat.push(`    ) else (`);
    bat.push(`        echo Successfully pulled repository %repoName%.`);
    bat.push(`    )`);
    bat.push(`) else (`);
    bat.push(`    echo Cloning repository: %~1`);
    bat.push(`    set "safeRepoPath=%~1"`);
    bat.push(`    set "safeRepoPath=%safeRepoPath:\\=\\\\%"`);
    bat.push(`    %gitPath% clone %~1`);
    bat.push(`    echo  %gitPath% clone %~1`);
    bat.push(`    if errorlevel 1 (`);
    bat.push(`        echo Failed to clone repository %~1. Please check network connection and permissions.`);
    bat.push(`    )`);
    bat.push(`)`);
    bat.push(``);
    bat.push(`shift`);
    bat.push(`goto loop_repos`);
    bat.push(`endlocal`);
    bat.push(`goto :EOF`);
    bat.push(``);

    // Write footer
    bat.push(`:end`);
    bat.push(`echo.`);
    bat.push(`echo All operations completed.`);
    bat.push(`pause`); // Ensure the window stays open after completion
    bat.push(`exit /b 0`);

    // Write file
    fs.writeFileSync(outputPath, bat.join('\r\n'), 'utf8');
    console.log(`✅ BAT script has been generated: ${outputPath}`);
}

exports.main = async function main() {
    try {
        console.log('📥 Downloading configuration file...');
        const iniContent = await downloadIniFile(CONFIG_URL);
        const config = parseIni(iniContent);
        console.log('📦 Parsed groups:', Object.keys(config));

        // Ensure the temporary directory exists
        ensureDirectoryExists(TEMP_DIR);

        // Generate dynamic output path with timestamp
        const timestamp = new Date().toISOString().replace(/[-:.T]/g, '').substring(0, 14);
        const outputFileName = `${BAT_FILE_PREFIX}_${timestamp}.bat`;
        const outputPath = path.join(TEMP_DIR, outputFileName);

        generateBat(config, outputPath);

        // Open the generated batch file using the default double-click action
        exec(`start "" "${outputPath}"`, { shell: true }, (error, stdout, stderr) => {
            if (error) {
                console.error(`Error executing batch file: ${error.message}`);
                return;
            }
            if (stderr) {
                console.error(`Batch file execution stderr: ${stderr}`);
                return;
            }
            console.log(`Batch file executed successfully. Output:\n${stdout}`);
        });
    } catch (err) {
        console.error('❌ An error occurred:', err.message);
    }
}